package com.tn.service.dwr;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.StringUtils;

import com.tn.bo.Company;
import com.tn.bo.CreditMemo;
import com.tn.bo.Invoice;
import com.tn.bo.POHeader;
import com.tn.bo.Payment;
import com.tn.bo.SearchRequest;
import com.tn.bo.SearchResponse;
import com.tn.dao.CompanyDAO;
import com.tn.dao.InvoiceDAO;
import com.tn.dao.PurchaseOrderDAO;
import com.tn.xfer.DwrResponse;

public class SearchServiceDwr {
	private static List<Company> allCompanies;
	private static long lastRefreshedTimeMs;
	static {
		synchronized (SearchServiceDwr.class) {
			loadRefreshListOfAllCompanies();
		}
	}
	
	private static void loadRefreshListOfAllCompanies(){
			System.out.println("fetching list of all companies, start ....");
			synchronized (SearchServiceDwr.class) {
				allCompanies = new CompanyDAO().findAllCompanies();
				lastRefreshedTimeMs = System.currentTimeMillis();
			}
			System.out.println("fetching list of all companies, end ....");
		
	}

	@SuppressWarnings("unchecked")
	public DwrResponse searchDocuments(SearchRequest search) {
		DwrResponse response = new DwrResponse("SEARCH_GENERAL", 0);
		List results = null;
		if ("PO".equals(search.getDocumentType())) {
			results = searchForPO(search);
		} else if ("INV".equals(search.getDocumentType())) {
			results = searchForInvoice(search);
		} else if ("CMEMO".equals(search.getDocumentType())) {
			results = searchForCreditMemo(search);
		} else if ("PMT".equals(search.getDocumentType())) {
			results = searchForPayment(search);
		}

		SearchResponse resp = new SearchResponse(search.getDocumentType(),
				results);
		response.setObjRespOrError(resp);
		return response;
	}

	private List<Payment> searchForPayment(SearchRequest search) {
		Map<String, Object> filters = new HashMap<String, Object>();
		if ("SENT".equals(search.getSentReceived())) {
			filters.put("paymentOriginatorCompany", search.getCompanyId());
		} else {
			filters.put("paymentRecipientMainCompany", search.getCompanyId());
		}

		// from date / to date
		if (search.getFromDate() != null) {
			filters.put("paymentDate >= ", search.getFromDate());
		}

		if (search.getToDate() != null) {
			filters.put("paymentDate <= ", search.getToDate());
		}

		// from amount / to amount

		if (search.getFromAmount() != null) {
			filters.put("totalPaymentAmount >= ", search.getFromAmount());
		}

		if (search.getToAmount() != null) {
			filters.put("totalPaymentAmount <= ", search.getToAmount());
		}

		InvoiceDAO dao = new InvoiceDAO();
		List<Payment> headers = dao.searchPaymentByFilters(filters);
		return headers;
	}

	private List<CreditMemo> searchForCreditMemo(SearchRequest search) {
		Map<String, Object> filters = new HashMap<String, Object>();
		if ("SENT".equals(search.getSentReceived())) {
			filters.put("originatingCompany", search.getCompanyId());
		} else {
			filters.put("creditMemoToCompany", search.getCompanyUid());
		}

		// from date / to date
		if (search.getFromDate() != null) {
			filters.put("creditMemoDate >= ", search.getFromDate());
		}

		if (search.getToDate() != null) {
			filters.put("creditMemoDate <= ", search.getToDate());
		}

		// from amount / to amount

		if (search.getFromAmount() != null) {
			filters.put("totalCreditMemoAmount >= ", search.getFromAmount());
		}

		if (search.getToAmount() != null) {
			filters.put("totalCreditMemoAmount <= ", search.getToAmount());
		}

		InvoiceDAO dao = new InvoiceDAO();
		List<CreditMemo> headers = dao.searchCreditMemoByFilters(filters);
		return headers;
	}

	private List<Invoice> searchForInvoice(SearchRequest search) {
		Map<String, Object> filters = new HashMap<String, Object>();
		if ("SENT".equals(search.getSentReceived())) {
			filters.put("mainSupplierCompnay", search.getCompanyId());
		} else {
			filters.put("invoicedToCompany", search.getCompanyUid());
		}

		// from date / to date
		if (search.getFromDate() != null) {
			filters.put("invoiceDate >= ", search.getFromDate());
		}

		if (search.getToDate() != null) {
			filters.put("invoiceDate <= ", search.getToDate());
		}

		// from amount / to amount

		if (search.getFromAmount() != null) {
			filters.put("totalInvoiceAmount >= ", search.getFromAmount());
		}

		if (search.getToAmount() != null) {
			filters.put("totalInvoiceAmount <= ", search.getToAmount());
		}

		InvoiceDAO dao = new InvoiceDAO();
		List<Invoice> headers = dao.searchInvoiceByFilters(filters);
		return headers;
	}

	private List<POHeader> searchForPO(SearchRequest search) {
		Map<String, Object> filters = new HashMap<String, Object>();
		if ("SENT".equals(search.getSentReceived())) {
			filters.put("orderCompany", search.getCompanyUid());
		} else {
			filters.put("orderSupplier", search.getCompanyUid());
		}

		// from date / to date
		if (search.getFromDate() != null) {
			filters.put("orderDate >= ", search.getFromDate());
		}

		if (search.getToDate() != null) {
			filters.put("orderDate <= ", search.getToDate());
		}

		// from amount / to amount

		if (search.getFromAmount() != null) {
			filters.put("orderAmount >= ", search.getFromAmount());
		}

		if (search.getToAmount() != null) {
			filters.put("orderAmount <= ", search.getToAmount());
		}

		PurchaseOrderDAO dao = new PurchaseOrderDAO();
		List<POHeader> headers = dao.searchByFilters(filters);

		if (!"SENT".equals(search.getSentReceived())
				&& (headers == null || headers.isEmpty())) {
			filters.put("orderSupplier", search.getCompanyId());
			headers = dao.searchByFilters(filters);
		}
		return headers;
	}

	/*public DwrResponse searchSupplier(SearchRequest request) {
		DwrResponse resp = new DwrResponse("FIND_COMPANY", 0);
		CompanyDAO dao = new CompanyDAO();
		// Hashset to filter out results.
		Set<Company> filterdResults = new HashSet<Company>();
		List<Company> retList = new ArrayList<Company>();

		if (StringUtils.isNotEmpty(request.getCompanyName())) {
			List<Company> list = dao.findCompanyByNamePattern(request
					.getCompanyName());
			if (list != null) {
				for (Company c : list) {
					filterdResults.add(c);
				}
			}
		}

		retList.addAll(filterdResults);
		resp.setObjRespOrError(retList);
		return resp;
	}*/

	public DwrResponse searchSupplier(SearchRequest request) {
		//Check how stale the list of companies is.
		long diff = System.currentTimeMillis() - lastRefreshedTimeMs;
		
		//TODO: 1 hour >> Make this configurable.
		if(diff >= 60*60*1000){
			loadRefreshListOfAllCompanies();
		}
		
		DwrResponse resp = new DwrResponse("FIND_COMPANY", 0);
		

		Set<Company> filterdResults = new HashSet<Company>();

		if (allCompanies == null || allCompanies.size() <= 0) {
			return resp;
		}

		for (Company company : allCompanies) {
			if (
			// By Company Name
			this.searchTermFound(company.getCompanyName(),
					request.getCompanyName())
					// By Doing Business as
					|| this.searchTermFound(
							company.getCompanyDoingBusinessAs(),
							request.getDoingBusinessAs())
					// By Company Domain
					|| this.searchTermFound(company.getCompanyDomain(),
							request.getDoingBusinessAs())
					// By Company Phone
					|| this.searchTermFound(company.getPhone(),
							request.getPhone())
					// By Company City
					|| this.searchTermFound(company.getCity(),
							request.getCity())
					// By Company State
					|| this.searchTermFound(company.getState(),
							request.getState())
					// By Company Country
					|| this.searchTermFound(company.getCountry(),
							request.getCountry())) {
				filterdResults.add(company);
			}
		}

		resp.setObjRespOrError(filterdResults.toArray());
		return resp;
	}

	private boolean searchTermFound(String data, String searchTerm) {
		return (StringUtils.isNotEmpty(data)
				&& StringUtils.isNotEmpty(searchTerm) && data.toLowerCase()
				.indexOf(searchTerm.toLowerCase()) >= 0);
	}

}
